package fstvis;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.StringTokenizer;
import fstvis.SciNotationFormat;
import jsc.correlation.LinearCorrelation;
import jsc.datastructures.PairedData;

public class FstData {
	int time;
	int layer;
	String species;
	File fstFile;
	Field fld;

	public int getTime() {
		return time;
	}


	public void setTime(int time) {
		this.time = time;
	}


	public int getLayer() {
		return layer;
	}


	public void setLayer(int layer) {
		this.layer = layer;
	}


	public String getSpecies() {
		return species;
	}


	public void setSpecies(String species) {
		this.species = species;
	}


	public FstData(File fstFile, String species, int time, int layer) {
		this.fstFile = fstFile;
		this.species = species;
		this.time = time;
		this.layer = layer;
	}

	public void setData(Field fld) {
		this.fld = fld;
	}
	
	public void loadData() {
		String command = "/home/matt/aurams/trunk/vis/fortran/extractData";
		String params = new String(fstFile.getParent() + "/ " + fstFile.getName() + " " + species + " " + time + " " + layer);

		System.out.println(command + " " + params);
		
		try {
			Process prcs = Runtime.getRuntime().exec(command + " " + params);
			InputStream in = prcs.getInputStream();
			StringBuffer sb = new StringBuffer(17*106);
			int ch, ni = 0, nj = 0;
			int i = 0, j = 0;
			String line = new String();
			NumberFormat numf = new DecimalFormat();
			NumberFormat numsn = new SciNotationFormat("0.###E0");
			String nums = new String(); 
			Number num = 0;

			char nl = new String("\n").charAt(0);
	
			while ( ( ch = in.read() ) != -1 ) {
				if ((char)ch == nl) {
					// We're in a new line
					line = sb.toString();
					sb.replace(0, sb.length(), ""); // clear the line
					//System.out.println("line: " + line);
				
					// First lets look for the line "NI= 150, NJ= 106, NK=   1"
					if (line.contains("NI=")) {
						try {
							nums = line.substring(line.indexOf("=")+1, line.indexOf(","));
							nums = nums.replaceAll(" ", "");
							num = numf.parse(nums);

							ni = num.intValue();

							line = line.substring(line.indexOf(",") + 1);
							nums = line.substring(line.indexOf("=")+1, line.indexOf(","));

							nums = nums.replaceAll(" ", "");
							num = numf.parse(nums);
							
							nj = num.intValue();
							break;
						} catch (java.text.ParseException ex) {
							System.err.println("Could not parse number in " + line + "\n" + ex);
							System.exit(1);
						}
					}
				} else {
					sb.append((char) ch);
				}
			}


			// Define our field
			fld = new Field(ni, nj, false);
				
			sb.replace(0, sb.length(), ""); // clear the line
			while ( ( ch = in.read() ) != -1 ) {
				if ((char)ch == nl) {
					// We're in a new line
					line = sb.toString();
					sb.replace(0, sb.length(), ""); // clear the line
					//System.out.println("line: " + line);

					StringTokenizer st = new StringTokenizer(line, ",");
					j = 0;
					while (st.hasMoreTokens()) {
	                    try {
	                        nums = st.nextToken();
	                        nums = nums.replaceAll(" ", "");
	                        num  = numsn.parse(nums);
	                    } catch (java.text.ParseException ex) {
	                        System.out.println("Count not parse: " + nums);
	                        break;
	                    }
	                    fld.setValue(i, j, num.doubleValue());
	                    
	                    j++; // increment column counter
					}
					
					i++; // increment row counter
				} else {
					sb.append((char) ch);
				}
			}

		} catch (IOException ex) {
			System.out.println("Error reading data: " + ex);
		}
	}

	public final Field getField() {
		return this.fld;
	}

	public static FstData Difference(FstData data_a, FstData data_b) {
		int[] size = data_a.getField().getSize();
		Field res = new Field(size[0], size[1], false);

		double[][] fa = data_a.getField().getField();
		double[][] fb = data_b.getField().getField();
		
		for (int i=0; i<size[0]; i++) {
			for (int j=0; j<size[1]; j++) {
				res.setValue(i, j, fb[i][j] - fa[i][j]);
			}
		}

		FstData dat = new FstData(null, new String(data_b.getSpecies() + " - " + data_a.getSpecies()), data_a.getTime(), data_a.getLayer());
		dat.setData(res);
		return dat;
	}
	
	public static void main(String[] args) {
		System.out.println("Testing the stats");

		int ni = 4;
		int nj = 6;
		int i, j;
		double val;
		Field f1 = new Field(ni, nj);
		Field f2 = new Field(ni, nj);

		/////////////////////////////////////////////////////////////////
		// Set all the values to be the same, R^2 should be 1
		for (i=0; i<ni; i++) {
			for (j=0; j<ni; j++) {
				val = Math.random(); 
				f1.setValue(i, j, val); f2.setValue(i, j, val);
			}
		}

		ComparisonStats s = new ComparisonStats(f1, f2);
		double r2 = s.getR2();
		System.out.print("Test 2: f2 = 2*f1 ==> R^2 = 1");
		if (r2 != 1) System.out.println("  [FAIL]");
		else System.out.println("  [PASS]");
		/////////////////////////////////////////////////////////////////

		/////////////////////////////////////////////////////////////////
		// f2 = 2*f1, R should equal 1
		for (i=0; i<ni; i++) {
			for (j=0; j<ni; j++) {
				val = Math.random(); 
				f1.setValue(i, j, val); f2.setValue(i, j, 2*val);
			}
		}

		s = new ComparisonStats(f1, f2);
		r2 = s.getR2();
		System.out.print("Test 2: f2 = 2*f1 ==> R^2 = 1");
		if (r2 != 1) System.out.println("  [FAIL]");
		else System.out.println("  [PASS]");
		/////////////////////////////////////////////////////////////////

		/////////////////////////////////////////////////////////////////
		// Comparing to Java function
		for (i=0; i<ni; i++) {
			for (j=0; j<ni; j++) {
				val = Math.random();
				f1.setValue(i, j, val); f2.setValue(i, j, 1);
			}
		}

		double[] d1 = f1.getField1D().getField();
		double[] d2 = f2.getField1D().getField();
		PairedData pd = new PairedData(d1, d2);
		
		s = new ComparisonStats(f1, f2);
		r2 = s.getR();
		double r2lc = LinearCorrelation.correlationCoeff(pd);
		System.out.print("Test 3: Does our calculation match the JSC's calculation?");
		if (Math.abs(r2 - r2lc) > 0.0001) System.out.println("  [FAIL], R^2 = " + r2 + ", r2lc = " + r2lc + ", err = " + Math.abs(r2 - r2lc));
		else System.out.println("  [PASS]");
		/////////////////////////////////////////////////////////////////

	}

}